package game.server;

import game.Card;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;


import client.GUI.Window;

public class EvalHand {
	private ArrayList<Card> availCards = new ArrayList<Card>();
	/**
	 * checks all possible combinations with cards in players hand and on table
	 * Hands Integer range values (X = your hand)
	 * No hand 5 <= X <= 27
	 * Pair 28 <= X <= 196
	 * Two pair 200 <= X <= 1080
	 * Three of a kind 1086 <= X <= 7602
	 * Straight 7620 <= X <= 22860
	 * Flush 22880 <= X <= 68640
	 * Full house 68652 <= X <= 389028
	 * Four of a kind 389032 <= X <= 2723224
	 * Straight Flush 2723240 <= X <= 8169720
	 * @param cards available card list
	 * @return players cards combination
	 */
	public int evaluate(ArrayList<Card> cards){
		int outCome = 0;
		if(outCome == 0){
			outCome = StraightFlush(cards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = fourOfaKind(availCards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = fullHouse(availCards);
		}
		
		if(outCome == 0){
			availCards = sortSuit(cards);
			outCome = flush(availCards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = straight(availCards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = threeOfaKind(availCards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = twoPair(availCards);
		}
		if(outCome == 0){
			availCards = sortValue(cards);
			outCome = pair(availCards);
		}
		if(outCome==0){
			availCards = sortValue(cards);
			outCome = noHand(availCards);
		}
		return outCome;
	}
	/**
	 * loops through cards and checks if they meet straight flush criteria
	 * @param cards available card list
	 * @return result (straight flush)
	 */
	private int StraightFlush(ArrayList<Card> cards){
		ArrayList<String> tempS = new ArrayList<String>();
		int result = 0;
		int counterS = 0;
		int counterV = 0;
		int first = 0;
		for(int i=1;i<cards.size();i++){
			cards = sortSuit(cards);
			if(cards.get(i).getSuit().equals(cards.get(i-1).getSuit())) {
				if(tempS.isEmpty() || tempS.contains(cards.get(i).getSuit()) ){
					tempS.add(cards.get(i-1).getSuit());
					counterS++;
				}
				cards = sortValue(cards);
				if((cards.get(i).getValue()-cards.get(i-1).getValue())==1 ||
						(cards.get(i).getValue()-cards.get(i-1).getValue())==0){
					result += cards.get(i).getValue();
					if(first == 0){
						first = cards.get(i-1).getValue();
					}
						counterV++;
					}
				if(counterS==4 && counterV==4){
					result += first;
					return 136162*result;
				}else{result = 0;}
			}
		}
		//return 8;
		return result;	
	}
	/**
	 * loops through cards and checks if they meet Four of a Kind criteria
	 * @param cards available card list
	 * @return result (four of a kind)
	 */
	private int fourOfaKind(ArrayList<Card> cards){
		int result = 0;
		ArrayList<Integer> temp = new ArrayList<Integer>();
		int counter = 0;
		int first = 0;
		for(int i=1;i<cards.size();i++){
			if(cards.get(i).getValue()==cards.get(i-1).getValue()){
				if(temp.isEmpty() || temp.contains(cards.get(i).getValue()) ){
					temp.add(cards.get(i).getValue());
					if(result==0){
						first += cards.get(i).getValue();
						
					}
					counter++;
				}
				if(counter==3){
					result = 4*48629*first;
					return result;
				}
			}
		}
		return result;
	}
	/**
	 * loops through cards and checks if they meet Full House criteria
	 * @param cards available card list
	 * @return result (full house)
	 */
	@SuppressWarnings("unchecked")
	private int fullHouse(ArrayList<Card> cards){
		int result = 0;
		ArrayList<Integer> tempTOAK = new ArrayList<Integer>();
		ArrayList<Card> temp = new ArrayList<Card>();
		ArrayList<Card> tempCard = new ArrayList<Card>();
		temp = (ArrayList<Card>) cards.clone();
		int counterTOAK = 0;
		int counterPAIR = 0;
		int first = 0;
		int second = 0;
		boolean toak=false;
		boolean pair=false;
		for(int i=1;i<temp.size();i++){
			if(temp.get(i).getValue()==temp.get(i-1).getValue()){
				if(tempTOAK.isEmpty() || tempTOAK.contains(temp.get(i).getValue()) ){
					tempTOAK.add(temp.get(i).getValue());
					counterTOAK++;
					if(first==0){
						first = cards.get(i-1).getValue();
					}
				//	result += cards.get(i).getValue();
					tempCard.add(temp.get(i-1));
				}
			}
		}
		if(counterTOAK==1){
			pair = true;
		}
		if(counterTOAK==2){
			toak = true;
		}
		for(Card c : tempCard){
			temp.remove(c);
		}
		tempTOAK.clear();
		for(int i=1;i<temp.size();i++){
			if(temp.get(i).getValue()==temp.get(i-1).getValue()){
				if(tempTOAK.isEmpty() || tempTOAK.contains(temp.get(i).getValue()) ){
					tempTOAK.add(temp.get(i).getValue());
					if(second==0){
						second = cards.get(i-1).getValue();
					}
				//	result += cards.get(i).getValue();
					counterPAIR++;
					tempCard.add(temp.get(i-1));
				}
			}
		}
		if(toak==true && counterPAIR == 1){
			result += second + first;
			return 5721*result;
		}
		if(pair==true && counterPAIR==2){
			result += second + first;
			return 5721*result;
		}
		return result;
	}
	/**
	 * loops through cards and checks if they meet flush criteria
	 * @param cards available card list
	 * @return result ( flush )
	 */
	private int flush(ArrayList<Card> cards){
		int result = 0;
		ArrayList<String> temp = new ArrayList<String>();
		int counter = 0;
		int first = 0;
		for(int i=1;i<cards.size();i++){
			if(cards.get(i).getSuit().equals(cards.get(i-1).getSuit())){
				if(temp.isEmpty() || temp.contains(cards.get(i).getSuit()) ){
					temp.add(cards.get(i-1).getSuit());
					if(first==0){
						first = cards.get(i-1).getValue();
					}
			//		result += cards.get(i).getValue();
					counter++;
				}
				if(counter==4){
					result += first;
					return 1144*result;
				}
			}
		}
		//return 5;
		return result;
	}
	/**
	 * loops through cards and checks if they meet straight criteria
	 * @param cards available card list
	 * @return result ( straight )
	 */
	private int straight(ArrayList<Card> cards){
		int counter = 0;
		int first = 0;
		int match = 0;
		int result = 0;
		for(int i=1;i<cards.size();i++){
			if((cards.get(i).getValue()-cards.get(i-1).getValue())==1 ||
					(cards.get(i).getValue()-cards.get(i-1).getValue())==0){
				if(first==0){
					first = cards.get(i-1).getValue();
				}
		//		result += cards.get(i).getValue();
				counter++;
				if((cards.get(i).getValue()-cards.get(i-1).getValue())==0){
					match++;
					if(match==2){
						return result;
					}
				}
				if(counter>=4){
					result += first;
					return 381*result;
				}
			}else{counter = 0;}
		}
		//return 4;
		return result;	
	}
	/**
	 * loops through cards and checks if they meet three of a kind criteria
	 * @param cards available card list
	 * @return result (three of a kind)
	 */
	private int threeOfaKind(ArrayList<Card> cards){
		int result = 0;
		ArrayList<Integer> temp = new ArrayList<Integer>();
		int counter = 0;
		for(int i=1;i<cards.size();i++){
			if(cards.get(i).getValue()==cards.get(i-1).getValue()){
				if(temp.isEmpty() || temp.contains(cards.get(i).getValue()) ){
					temp.add(cards.get(i-1).getValue());
					counter++;
				}
				if(counter==2){
					result = 3*181*cards.get(i).getValue();
				}
			}
		}
	//	return 3;
		return result;
	}
	/**
	 * loops through cards and checks if they meet two pair criteria
	 * @param cards available card list
	 * @return result ( two pair)
	 */
	@SuppressWarnings("unchecked")
	private int twoPair(ArrayList<Card> cards){
		int result = 0;
		int first = 0;
		int second = 0;
		int secOut = 0;
		ArrayList<Card> temp1 = new ArrayList<Card>();
		Card temp = null;
		temp1 = (ArrayList<Card>) cards.clone();
		int counter = 0;
		for(int i=1;i<temp1.size();i++){
			if(temp1.get(i).getValue()==temp1.get(i-1).getValue()){
				counter++;
				if(first==0){
					secOut = 2*temp1.get(i).getValue();
				}
				temp = temp1.get(i);
				break;
			}
		}
		temp1.remove(temp);
		for(int j=1;j<temp1.size();j++){
			if(temp1.get(j).getValue()==temp1.get(j-1).getValue()){
				counter++;
				if(second==0){
					secOut += 2*temp1.get(j).getValue();
				}
				break;
			}
		}if(counter==2){
			result = 20*secOut;
		}
	//	return 2;
		return result;
	}
	/**
	 * loops through cards and checks if they meet pair criteria
	 * @param cards available card list
	 * @return result (pair)
	 */
	private int pair(ArrayList<Card> cards){
		int result = 0;
		int counter = 0;
		for(int i=1;i<cards.size();i++){
			if(cards.get(i).getValue()==cards.get(i-1).getValue()){
				counter++;
				if(counter==1){
					result = 2*cards.get(i).getValue();
				}
			}
		}
		//return 1;
		return result*7;
	}
	/**
	 * Picks out two last cards(2 highest values) from cards list and adds them
	 * @param cards available card list
	 * @return result (no hand)
	 */
	private int noHand(ArrayList<Card> cards){
		int result = 0;
		result += cards.get(cards.size()-1).getValue();
		result += cards.get(cards.size()-2).getValue();
		return result;
	}
	/**
	 * Sorts cards arraylist from low to high order by card value
	 * @param availCards available card list
	 * @return sorted arraylist in numeric order
	 */
	private ArrayList<Card> sortValue(ArrayList<Card> availCards){
		ArrayList<Integer> temp = new ArrayList<Integer>();
		ArrayList<Card> out = new ArrayList<Card>();
		for(int i = 0;i < availCards.size();i++){
			temp.add(availCards.get(i).getValue());
		}
		Collections.sort(temp);
		for(int i=0;i<temp.size();i++){
			for(int j=0;j<availCards.size();j++){
				if(temp.get(i)==availCards.get(j).getValue()){
					if(!out.contains(availCards.get(j))){
						out.add(availCards.get(j));
					}
				}
			}
		}
		return out;
	}
	/**
	 * Sorts cards arraylist alphabetacally
	 * @param availCards available card list
	 * @return sorted arraylist in alpabetacal order
	 */
	private ArrayList<Card> sortSuit(ArrayList<Card> availCards){
		ArrayList<String> temp = new ArrayList<String>();
		ArrayList<Card> out = new ArrayList<Card>();
		for(int i = 0;i < availCards.size();i++){
			temp.add(availCards.get(i).getSuit());
		}
		Collections.sort(temp);
		for(int i=0;i<temp.size();i++){
			for(int j=0;j<availCards.size();j++){
				if(temp.get(i)==availCards.get(j).getSuit()){
					if(!out.contains(availCards.get(j))){
						out.add(availCards.get(j));
					}
				}
			}
		}
		return out;
	}
	public static void main(String[] args) {
		ArrayList<Card> list = new ArrayList<Card>();
		list.add(new Card("Spades", 4));
		list.add(new Card("Diamonds", 4));
		list.add(new Card("Clubs", 4));
		list.add(new Card("Clubs", 5));
		EvalHand ev = new EvalHand();
		System.out.println(ev.evaluate(list));
	}
}
